#ifndef LIB_TYPEDCALLBACK_HH
#define LIB_TYPEDCALLBACK_HH


/*! \file This file defines a generic callback mechanism for C++ objects.
 * The callback is an object that is bound to a user object in a type-safe
 * manner at compile-time.
 *
 * \par Overview
 * An overloaded C++ function-call operator is used to implement a
 * flexible callback mechanism. One side (the service user) instantiates a
 * callback object and binds it to one of its own object. The other
 * side (service provider) receives the callback object and holds on to it.
 * At a later point in time, the service-provider invokes the callback object.
 * This lands on the service user's object that is bound to the callback.
 *
 * The binding between a user application's object and the callback object
 * is type-checked at compile-time. A user-type is specified for each
 * callback object that is instantiated. The callback object is bound to a
 * specific user object during initialization.  This callback object then
 * invokes an overloaded C++ operator()() on that object. This member
 * function takes a parameter that is a pointer to the callback object
 * itself.
 *
 * \par Example:
 * \code
 * struct ServiceProvider
 * {
 *     void hello(TypedCallbackInterface* p)  { cb = p; }
 *     void goodbye()                           { (*cb)(); }
 *     TypedCallbackInterface* cb;
 * };
 * 
 * class MyClass;
 * typedef TypedCallback< MyClass, MyData>  MyCB;
 * 
 * struct MyClass
 * {
 *     virtual int operator()(MyCB* p)
 *     {cout << "callback invoked... " << endl;}
 * };
 * 
 * int
 * main()
 * {
 *     MyData           myData;
 *     MyClass          handler;
 *     MyCB*            pbak = new MyCB( &handler, myData);
 *     ServiceProvider  server;
 * 
 *     server.hello( pbak );    //registers callback
 *     server.goodbye();        //simulated event prompts server to invoke CB
 * }
 * \endcode
 *
 * \par Binding:
 * This base class and its template-based co-conspirator allow creating
 * callbacks that are not bound to an object at construction time
 * (e.g. inside vectors), or that their binding can be changed at run-time
 * (e.g. for delegation). Such un-bound callbacks are bound using
 * the derived class's "set()" method.
 *
 * \code
 *     MyCB*        pbak = new MyCB();
 *     MyClass      handler;
 *     pbak->set( &handler, myData);   //bind callback to an object
 * \endcode
 */


/*! \brief The interface class is useful primarily for the service-provider
 * which handles callback objects in a generic fashion.
 *
 * The service-provider invokes callback simply by invoking its
 * "operator()(void)" method - e.g.
 * \code
 *        (* pCallback)();
 * \endcode
 * \note
 * This class is never instantiated directly.
 */
class TypedCallbackInterface
{
 public:
    virtual ~TypedCallbackInterface() {}
    virtual int operator()(void) = 0;
    bool isBound(void) const {return cbBound;}

 protected:
    TypedCallbackInterface() {cbBound = false;}

 protected:
    bool    cbBound; //initialized

 private:
    // TBD: copy & assignment are questionable!?!?
};



/*! \brief This class declares a type-safe callback object.
 *
 * An object of this type is created and given to a service provider
 * library. This object is bound at runtime in a type-safe manner to a
 * specific object. See an example at the top of this file.
 *
 * The client side which creates the callback object must implement the
 * following overloaded operator() method in some class and bind an
 * instance of that type to the callback object as follows:
 *
 * \code
 *          typedef TypedCallback< SomeClass, SomeDataType> MyCallback;
 *          class SomeClass { ...
 *              virtual int operator()(MyCallback*);
 *          };
 *          ...
 *          SomeClass   myObject;
 *          MyCallback  pcb = new MyCallback( &myObject, ...);
 * \endcode
 * \note
 * In general, the callback object cannot be a local variable - i.e. it
 * has static or dynamic extent because it has to live as long as it's
 * regarded as "usable" by the service-provider library.
 *
 * It is also possible to derive from the callback class and handle the
 * callback event directly as shown below. This may be easier to program and
 * reduce the number of object allocations.
 * \code
 *          class SomeClass : public MyCallback
 *          { ...
 *              SomeClass() : MyCallback( this, ...)
 *              virtual int operator()(MyCallback*);
 *          };
 * \endcode
 * \b Note: This derived object is only considered a \i single callback object.
 * Therefore, it can only be used as \i one \i callback at a time!
 * Also, since the base class of the callback object has "internal state",
 * it is not possible to derive from multiple types of callbacks.
 */
// @@@ Future: TO-DO: a third class parameter can specify an
// optional exception behavior for invoking un-bound callbacks!
template< typename POBJ_, typename COOKIE_ = int>
class TypedCallback
    : public TypedCallbackInterface
{
public:
    TypedCallback() {}
    TypedCallback( POBJ_* obj, COOKIE_ key = 0) {set( obj, key);}
    virtual ~TypedCallback() {}

    TypedCallback& set( POBJ_* obj, COOKIE_ key = 0)
    {
        userobj = obj;
        cook    = key;
        cbBound = true;
        return *this;
    }

    virtual int operator()(void) {return isBound() ? (*userobj)( this ) : 0;}
    COOKIE_& cookie(void) {return cook;}

protected:
    POBJ_*    userobj;
    COOKIE_   cook;
};

#endif /*LIB_TYPEDCALLBACK_HH*/
